package org.lmind.example.common.service.notify;

import java.io.File;
import java.io.IOException;
import java.io.StringWriter;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;

import org.lmind.example.common.api.Mail;
import org.lmind.example.common.api.MailService;
import org.lmind.example.common.api.notify.Transmitter;
import org.lmind.example.common.api.notify.TransmitterNames;
import org.lmind.example.common.core.UnhandledException;

import freemarker.cache.FileTemplateLoader;
import freemarker.cache.StringTemplateLoader;
import freemarker.template.Configuration;
import freemarker.template.Template;
import freemarker.template.TemplateException;

public class MailTransmitter implements Transmitter {
	
	private String templatePath;
	
	private MailService mailService;
	
	private String from;

	/**
	 * @return the templatePath
	 */
	public String getTemplatePath() {
		return templatePath;
	}

	/**
	 * @param templatePath the templatePath to set
	 */
	public void setTemplatePath(String templatePath) {
		this.templatePath = templatePath;
	}

	/**
	 * @return the mailService
	 */
	public MailService getMailService() {
		return mailService;
	}

	/**
	 * @param mailService the mailService to set
	 */
	public void setMailService(MailService mailService) {
		this.mailService = mailService;
	}

	public String getFrom() {
		return from;
	}

	public void setFrom(String from) {
		this.from = from;
	}

	/* (non-Javadoc)
	 * @see org.lmind.example.common.api.notify.Transmitter#getName()
	 */
	@Override
	public String getName() {
		return TransmitterNames.EMAIL;
	}

	/* (non-Javadoc)
	 * @see org.lmind.example.common.api.notify.Transmitter#notifyMessage(java.lang.String, java.lang.Object, java.lang.Object[])
	 */
	@Override
	public void notifyMessage(String template, Object message, Object... to) {
		TemplateMeta meta = loadTemplateMeta(template);
		parseTemplateMeta(meta, message, (String)to[0]);
	}
	
	protected String doTemplateFile(String template, Object message) {
		try {
			FileTemplateLoader loader = new FileTemplateLoader(new File(templatePath));
			Configuration cfg = new Configuration();
			cfg.setTemplateLoader(loader);
			Template temp = cfg.getTemplate(template);
			StringWriter writer = new StringWriter();
			temp.process(message, writer);
			return writer.toString();
		} catch (IOException e) {
			throw new UnhandledException(e);
		} catch (TemplateException e) {
			throw new UnhandledException(e);
		}
	}
	
	protected String doTemplateString(String template, Object message) {
		try {
			StringTemplateLoader loader = new StringTemplateLoader();
			loader.putTemplate("name", template);
			Configuration cfg = new Configuration();
			cfg.setTemplateLoader(loader);
			Template temp = cfg.getTemplate("name");
			StringWriter writer = new StringWriter();
			temp.process(message, writer);
			return writer.toString();
		} catch (IOException e) {
			throw new UnhandledException(e);
		} catch (TemplateException e) {
			throw new UnhandledException(e);
		}
	}
	
	protected TemplateMeta loadTemplateMeta(String templateName) {
		try {
			File working = new File(templatePath);
			File metaFile = new File(working, templateName + ".xml");
			JAXBContext jc = JAXBContext.newInstance(TemplateMeta.class, Object.class);
			TemplateMeta meta = (TemplateMeta)jc.createUnmarshaller().unmarshal(metaFile);
			return meta;
		} catch (JAXBException e) {
			throw new UnhandledException(e);
		}
	}
	
	protected void parseTemplateMeta(TemplateMeta meta, Object message, String to) {
		File working = new File(templatePath);
		String subject = doTemplateString(meta.getSubject(), message);
		String content = doTemplateFile(meta.getContentRef(), message);
		
		Mail mail = mailService.newMail();
		mail.setSubject(subject);
		mail.setBody(content, meta.getMimeType());
		for (String attachment : meta.getAttachments()) {
			mail.addAttachment(new File(working, attachment), null);
		}
		mailService.sendMail(mail, from, to);
	}
}
